import re
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.transforms import blended_transform_factory
from matplotlib.lines import Line2D
from matplotlib.collections import LineCollection
from copy import deepcopy


class ParseSignal:
    def __init__(self):
        pass

    def get_signal_infos(self):
        raise Exception(self.__class__.__name__, 'get_signal_infos')

    def edges_to_signals(self, signal_x_axes, rising_edges, amplitude=1.0):
        t = signal_x_axes
        signal = np.zeros_like(t)
        for start, end in rising_edges:
            signal += amplitude * ((t >= start) & (t < end)).astype(float)
        return signal

    def get_labels(self, label_line):
        return list(label_line.replace('"', '').split())

    def levels_to_signals(self, signal_lines):
        return [np.array([float(x) for x in signal_line.replace('"', '').split()], dtype=np.float64) for signal_line in signal_lines]

    def get_section_names(self, lines):
        label_pattern = r'^\[(.*)\]\n$'
        section_names = []
        for line in lines:
            obj = re.match(label_pattern, line)
            if not obj:
                continue
            section_names.append(obj.group(1).strip())
        return section_names

    def create_x_axes(self, signal_cycle):
        return np.arange(0, signal_cycle, dtype=np.float64)

    def calculate_rising_edges(self, edges, init_value=0):
        edges = deepcopy([edge for edge in edges if edge])
        if init_value == 1:
            edges.insert(0, 0)
        if len(edges) % 2:
            edges.append(np.inf)

        rising_edges = []
        for i in range(0, len(edges), 2):
                rising_edges.append((edges[i], edges[i + 1]))

        return rising_edges

    def get_file_lines(self, file_path):
        with open(file_path, 'r') as file:
            lines = [line for line in file.readlines() if line.strip()]
        return lines



class ParseSignalOld(ParseSignal):
    def __init__(self, file_path):
        super().__init__()
        self.file_path = file_path

    def get_signal_infos(self):
        lines = self.get_file_lines(self.file_path)
        labels = self.get_labels(lines[-1])
        signals = self.levels_to_signals(lines[:-1])
        x_axes = self.create_x_axes(len(signals[0]))

        return labels, x_axes, signals


class ParseSignalNewLong(ParseSignal):
    def __init__(self, file_path, section_name='timing'):
        super().__init__()
        self.file_path = file_path
        self.section_name = section_name.strip()

    def get_signal_infos(self):
        section_name = self.section_name

        lines = self.get_file_lines(self.file_path)
        section_names = self.get_section_names(lines)
        if section_name not in section_names:
            raise Exception(f"Section '{section_name}' not found in the file.")

        for line in lines:
            if line.strip().startswith(section_name):
                names, values = line.strip().split('=')
                section_lines = values.strip().split('\\0D\\0A')
                labels = self.get_labels(section_lines[-1])
                signals = self.levels_to_signals(section_lines[:-1])
                x_axes = self.create_x_axes(len(signals[0]))
                return labels, x_axes, signals

        raise Exception(f"Section '{section_name}' not found in the file.")


class ParseSignalNewShort(ParseSignal):
    def __init__(self, file_path, section_name='timing', signal_cycle=500, offset=0):
        super().__init__()
        self.file_path = file_path
        self.section_name = section_name.strip()
        self.signal_cycle = signal_cycle
        self.offset = offset

    def get_signal_infos(self):
        file_path = self.file_path
        section_name = self.section_name
        signal_cycle = self.signal_cycle
        offset = self.offset

        with open(file_path, 'r') as file:
            lines = file.readlines()

        section_names = self.get_section_names(lines)
        section_name = section_name.strip()
        if section_name not in section_names:
            raise Exception(f"Section '{section_name}' not found in the file.")

        for line in lines:
            if line.strip().startswith(section_name):
                names, values = line.strip().split('=')
                section_lines = values.strip().split('\\0D\\0A')
                labels = self.get_labels(section_lines[-1])

                signals = []
                x_axes = self.create_x_axes(signal_cycle)

                for section_line in section_lines[:-1]:
                    edges = [int(val) for val in section_line.replace('"', '').split()]
                    rising_edges = self.calculate_rising_edges(edges, init_value=0)
                    signals.append(self.edges_to_signals(x_axes, rising_edges))

                return labels, x_axes, signals

        raise Exception(f"Section '{section_name}' not found in the file.")


class ParseSignalEvk(ParseSignal):
    def __init__(self, signal_infos,section_name='timing', signal_cycle=500, offset=0):
        super().__init__()
        self.signal_infos = signal_infos
        self.section_name = section_name.strip()
        self.signal_cycle = signal_cycle
        self.offset = offset

    def get_signal_infos(self):
        signal_infos = self.signal_infos[self.section_name]
        signal_cycle = self.signal_cycle

        x_axes = self.create_x_axes(signal_cycle)
        signals = []
        labels = []
        for label, init_value, edges in signal_infos:
            rising_edges = self.calculate_rising_edges(edges, init_value=init_value)
            signals.append(self.edges_to_signals(x_axes, rising_edges))
            labels.append(label)

        return labels, x_axes, signals


class ParseSignalTicon(ParseSignal):
    def __init__(self, signal_infos, section_name='timing'):
        super().__init__()
        self.signal_infos = signal_infos
        self.section_name = section_name.strip()

    def get_signal_infos(self):
        pass


class DrawSignals:
    def __init__(self, plt, parse_signal:ParseSignal):
        self.plt = plt
        self._parse_signal = parse_signal

        self._signal_cycle = 0
        self.signal_x_axes = None
        self._signal_num = 1
        self._edge_points = None

        self._top_margin = 0.07
        self._bottom_margin = 0.05
        self._left_margin = 0.08
        self._right_margin = 0.01
        self._signal_height = self.calculate_signal_height()
        self._signal_width = self.calculate_signal_width()
        self._signal_amplitude = 0.7
        self._color = '#111111'

        self._min_label_gap = 0
        self.original_rc_params = None
        self.fig = None

    @property
    def signal_num(self):
        return self._signal_num

    @signal_num.setter
    def signal_num(self, value):
        self._signal_num = value
        self._signal_height = self.calculate_signal_height()

    @property
    def signal_cycle(self):
        return self._signal_cycle

    @signal_cycle.setter
    def signal_cycle(self, value:int):
        self._signal_cycle = value
        self.signal_x_axes = self._parse_signal.create_x_axes(value)

    @property
    def color(self):
        return self._color

    @color.setter
    def color(self, value:str):
        self._color = value

    @property
    def min_label_gap(self):
        return self._min_label_gap

    @min_label_gap.setter
    def min_label_gap(self, value:int):
        self._min_label_gap = value

    @property
    def top_margin(self):
        return self._top_margin

    @top_margin.setter
    def top_margin(self, value:float):
        self._top_margin = value
        self._signal_height = self.calculate_signal_height()

    @property
    def bottom_margin(self):
        return self._bottom_margin
    @bottom_margin.setter
    def bottom_margin(self, value:float):
        self._bottom_margin = value
        self._signal_height = self.calculate_signal_height()

    @property
    def left_margin(self):
        return self._left_margin

    @left_margin.setter
    def left_margin(self, value:float):
        self._left_margin = value
        self._signal_width = self.calculate_signal_width()

    @property
    def right_margin(self):
        return self._right_margin

    @right_margin.setter
    def right_margin(self, value:float):
        self._right_margin = value
        self._signal_width = self.calculate_signal_width()

    @property
    def signal_height(self):
        return self._signal_height

    @property
    def signal_width(self):
        return self._signal_width

    @property
    def signal_amplitude(self):
        return self._signal_amplitude

    @signal_amplitude.setter
    def signal_amplitude(self, value):
        self._signal_amplitude = value

    @property
    def default_rc_params(self):
        return {
            'font.size': 8,
            'svg.fonttype': 'none',
            'axes.unicode_minus': False,
            'font.family': 'Calibri',
            'lines.linewidth': 1.0
        }

    def calculate_signal_height(self):
        return (1 - self._top_margin - self._bottom_margin) / self._signal_num

    def calculate_signal_width(self):
        return 1 - self._left_margin - self._right_margin

    def rc_param_original(self):
        original_rc_params = plt.rcParams.copy()
        return original_rc_params

    def rc_param_update(self, rc_params):
        self.plt.rcParams.update(rc_params)

    def create_transform(self):
        fig = self.fig
        transform = blended_transform_factory(
            fig.transFigure,
            fig.transFigure
        )
        return transform

    def get_edge_points(self, x_axes, signals):
        edge_points = list(sorted(set(int(x_axes[idx]) for signal in signals for idx in self.find_edges(signal))))
        if edge_points[0] > 0:
            edge_points.insert(0, 0)
        #
        # if edge_points[-1] < self.signal_cycle-1:
        #     edge_points.append(self.signal_cycle-1)
        # self._edge_points = edge_points
        return edge_points

    def data_to_fig_x(self, x_val):
        signal_x_axes = self.signal_x_axes
        signal_width = self.signal_width
        left_margin = self.left_margin

        return (x_val - signal_x_axes[0]) / (signal_x_axes[-1] - signal_x_axes[0]) * signal_width + left_margin

    def create_figure(self, signals, signal_inches:float=0.25, per_inches:int=60):
        signal_cycle = self.signal_cycle
        edge_length= np.sqrt(self.signal_num * signal_inches * signal_cycle / per_inches)
        # x_axes = self.signal_x_axes
        # edge_points = sorted(set(x_axes[idx] for signal in signals for idx in self.find_edges(signal)))
        # min_interval = np.diff(np.array(edge_points)).min()
        figsize = (edge_length * 4 / 3, edge_length)
        # figsize = (8, 6)
        # if min_interval < 5:
        #     # from math import ceil
        #     self.rc_param_update({'font.size': 6})
        #     figsize = (max(8, edge_length) * 2, edge_length)

        fig = plt.figure(figsize=figsize, dpi=100)
        fig.patch.set_alpha(0.0)
        self.fig = fig
        return fig

    def draw_signals(self, signals, labels):
        signal_height = self.signal_height
        top_margin = self.top_margin
        signal_amplitude = self.signal_amplitude
        color = self.color
        t = self.signal_x_axes
        fig = self.fig

        for signal_idx, (label, signal) in enumerate(zip(labels, signals)):
            # 计算当前通道的垂直位置
            y_base = 1 - top_margin - (signal_idx + 1) * signal_height
            x_step = np.repeat(t, 2)[1:]
            y_step = np.repeat(signal, 2)[:-1]

            x_fig = self.data_to_fig_x(x_step)
            y_fig = y_base + y_step * signal_height * signal_amplitude

            line = Line2D(
                x_fig, y_fig,
                color=color,
                alpha=0.9,
                transform=fig.transFigure
            )

            fig.add_artist(line)

            fig.text(
                x=self.left_margin * 0.8,
                y=y_base + signal_height * 0.3,
                s=label,
                ha='right',
                va='center',
                color=color,
                transform=fig.transFigure
            )

    def find_edges(self, signal, threshold=0):
        diff = np.diff(signal, prepend=0)
        return np.flatnonzero(np.abs(diff) > threshold)

    def get_filtered_edges(self, signals):
        t = self.signal_x_axes
        # edge_points = sorted(set(t[idx] for signal in signals for idx in self.find_edges(signal)))
        edge_points = self.get_edge_points(t, signals)
        min_label_gap = self.min_label_gap

        filtered_edges = []
        prev_x = -np.inf
        for x in sorted(edge_points):
            if x - prev_x > min_label_gap:
                filtered_edges.append(x)
                prev_x = x
        return filtered_edges

    def draw_dotted_lines(self, signals):
        bottom_margin = self.bottom_margin
        top_margin = self.top_margin
        filtered_edges = self.get_filtered_edges(signals)
        color = self.color
        fig = self.fig
        for x_pos in filtered_edges:
            x_fig = self.data_to_fig_x(x_pos)

            fig.add_artist(Line2D(
                [x_fig, x_fig], [bottom_margin * 0.8, 1 - top_margin],
                color=color,
                linestyle=(0, (3, 2)),
                alpha=0.6,
                transform=fig.transFigure
            ))

            fig.text(
                x=x_fig, y=1 - top_margin + 0.01,
                s=f"{x_pos:.0f}",
                rotation=-90,
                ha='center',
                va='bottom',
                color=color,
                transform=fig.transFigure
            )


    def save_signals(self, *args, **kwargs):
        self.plt.savefig(*args, **kwargs)

    def process(self, save_path, font_size=8, rc_param:dict=None):
        labels, x_axes, signals = self._parse_signal.get_signal_infos()
        self.signal_num = len(signals)
        self.signal_cycle = len(signals[0])

        original_paras = self.rc_param_original()
        self.rc_param_update(self.default_rc_params)
        if rc_param:
            self.rc_param_update(rc_param)

        self.create_figure(signals,0.3, 20)
        self.draw_signals(signals, labels)
        self.draw_dotted_lines(signals)
        self.save_signals(save_path, dpi=100)

        self.rc_param_update(original_paras)

    def show_signals(self):
        self.plt.show()

    @staticmethod
    def simulate_signals(signal_cycle:int, edges_count:list, min_gap=5):
        np.random.seed(33)
        edges_init = np.random.choice([0, 1], len(edges_count))

        lin_arr = np.arange(0, signal_cycle, min_gap, dtype=np.int32)
        result = [np.random.randint(lin_arr[i], lin_arr[i+1]) for i in range(0, len(lin_arr), 2)]
        arr = np.array(result).clip(min_gap if np.sum(edges_init) else 0, signal_cycle)

        signal_infos = {}
        signal_infos['timing'] = [
            ['Channel {:02d}'.format(i), init, np.sort(np.random.choice(arr, size=edge_count, replace=False)).tolist()]
            for i, (init, edge_count) in enumerate(zip(edges_init, edges_count))]

        return signal_infos


class DrawSignalsSketchy(DrawSignals):
    # def get_edge_points(self, x_axes, signals):
    #     edge_points = list(sorted(set(int(x_axes[idx]) for signal in signals for idx in self.find_edges(signal))))
    #     if edge_points[0] > 0:
    #         edge_points.insert(0, 0)
    #     return edge_points

    def insert_points(self, arr):
        result = []
        for i in range(len(arr) - 1):
            result.append(arr[i])
            start = arr[i]
            end = arr[i + 1]
            step = (end - start) / 4  # 分为 4 等份

            for j in range(1, 4):
                result.append(start + step * j)
        result.append(arr[-1])
        return np.array(result)

    def create_figure(self, signals, signal_inches:float=0.25, per_inches:int=60):
        signal_cycle = self.signal_cycle
        figsize = (min(signal_cycle / per_inches, 8), self.signal_num * signal_inches)
        # figsize = (8, 6)

        fig = plt.figure(figsize=figsize, dpi=100)
        fig.patch.set_alpha(0.0)
        self.fig = fig
        return fig

    def data_to_fig_x(self, x_val):
        signal_x_axes = self.signal_x_axes
        signal_width = self.signal_width
        left_margin = self.left_margin
        return (x_val - signal_x_axes[0]) / len(self._edge_points) * signal_width + left_margin

    def draw_signals(self, signals, labels):
        signal_height = self.signal_height
        top_margin = self.top_margin
        signal_amplitude = self.signal_amplitude
        color = self.color
        t = self.signal_x_axes
        fig = self.fig
        edge_points = deepcopy(self._edge_points)
        if edge_points[-1] < self.signal_cycle - 1:
            edge_points.append(self.signal_cycle - 1)

        for signal_idx, (label, signal) in enumerate(zip(labels, signals)):
            # 计算当前通道的垂直位置
            y_base = 1 - top_margin - (signal_idx + 1) * signal_height
            x_step = np.repeat(np.arange(len(t[edge_points])), 2)[1:]
            y_step = np.repeat(signal[edge_points], 2)[:-1]

            x_fig = self.data_to_fig_x(x_step)
            y_fig = y_base + y_step * signal_height * signal_amplitude

            line = Line2D(
                x_fig, y_fig,
                color=color,
                alpha=0.9,
                transform=fig.transFigure
            )
            fig.add_artist(line)

            fig.text(
                x=self.left_margin * 0.8,
                y=y_base + signal_height * 0.3,
                s=label,
                ha='right',
                va='center',
                color=color,
                transform=fig.transFigure
            )


    def draw_dotted_lines(self, signals):
        bottom_margin = self.bottom_margin
        top_margin = self.top_margin
        color = self.color
        fig = self.fig

        for x_pos, value in enumerate(self._edge_points):
            x_fig = self.data_to_fig_x(x_pos)

            fig.add_artist(Line2D(
                [x_fig, x_fig], [bottom_margin * 0.8, 1 - top_margin],
                color=color,
                linestyle=(0, (3, 2)),
                alpha=0.6,
                transform=fig.transFigure
            ))

            fig.text(
                x=x_fig, y=1 - top_margin + 0.01,
                s=f"{value:.0f}",
                rotation=-90,
                ha='center',
                va='bottom',
                color=color,
                transform=fig.transFigure
            )

    def process(self, save_path, font_size=8, rc_param: dict = None):
        labels, x_axes, signals = self._parse_signal.get_signal_infos()
        self.signal_num = len(signals)
        self.signal_cycle = len(signals[0])
        # edge_points = list(sorted(set(int(x_axes[idx]) for signal in signals for idx in self.find_edges(signal))))
        # if edge_points[0] > 0:
        #     edge_points.insert(0, 0)
        # self._edge_points = edge_points
        self._edge_points = self.get_edge_points(x_axes, signals)
        original_paras = self.rc_param_original()
        self.rc_param_update(self.default_rc_params)
        if rc_param:
            self.rc_param_update(rc_param)

        self.create_figure(signals, 0.3, 60)
        self.draw_signals(signals, labels)
        self.draw_dotted_lines(signals)
        self.save_signals(save_path, dpi=100)

        self.rc_param_update(original_paras)


class DrawSignalStrategyOmit(DrawSignals):
    def __init__(self, plt, parse_signal: ParseSignal):
        super().__init__(plt, parse_signal)
        self._adjusted_arr = None
        self._shortened = 0
        self._omit_ranges = None

    def get_edge_points(self, x_axes, signals):
        edge_points = list(sorted(set(int(x_axes[idx]) for signal in signals for idx in self.find_edges(signal))))
        if edge_points[0] > 0:
            edge_points.insert(0, 0)

        if edge_points[-1] < self.signal_cycle-1:
            edge_points.append(self.signal_cycle-1)
        return edge_points

    def create_figure(self, signals, signal_inches: float = 0.25, per_inches: int = 60):
        signal_cycle = self.signal_cycle
        edge_length = np.sqrt(self.signal_num * signal_inches * signal_cycle / per_inches)
        # x_axes = self.signal_x_axes
        # edge_points = sorted(set(x_axes[idx] for signal in signals for idx in self.find_edges(signal)))
        # min_interval = np.diff(np.array(edge_points)).min()
        figsize = (edge_length * 4 / 3, edge_length)
        # figsize = (8, 6)
        # if min_interval < 5:
        #     # from math import ceil
        #     self.rc_param_update({'font.size': 6})
        #     figsize = (max(8, edge_length) * 2, edge_length)

        fig = plt.figure(figsize=figsize, dpi=100)
        fig.patch.set_alpha(0.0)
        self.fig = fig
        return fig

    def adjust_intervals(self, signals=None, threshold=50, zoom_factor=0.25, min_interval=5):
        # assert threshold * zoom_factor < 3, "zoom_factor should be greater than 0.25"
        edge_points = self._edge_points
        arr = np.array(edge_points)

        diffs = np.diff(arr)
        original_total = np.sum(diffs)

        large_diffs = diffs > threshold
        diffs[large_diffs] = np.minimum(np.floor(diffs[large_diffs] * zoom_factor), min_interval)
        adjusted_total = np.sum(diffs)
        shortened = original_total - adjusted_total

        adjusted_arr = np.empty_like(arr)
        adjusted_arr[0] = arr[0]
        for i in range(1, len(arr)):
            adjusted_arr[i] = adjusted_arr[i - 1] + diffs[i - 1]

        self._adjusted_arr = adjusted_arr
        self._shortened = shortened
        # self.signal_cycle = self.signal_cycle - shortened

        adjusted_signals  = np.array(signals)
        accumulation = 0
        omit_range = []
        last_edge = 0
        for old, adjusted in zip(arr, adjusted_arr):
            value = old - accumulation

            if value > adjusted:
                omit_range.append((last_edge, adjusted))
                adjusted_signals = np.delete(adjusted_signals, list(range(adjusted, value)), axis=1)
                accumulation += (value - adjusted)
            last_edge = adjusted
        self._omit_ranges = omit_range
        return adjusted_arr, shortened, [values for values in adjusted_signals], omit_range

    def is_omit(self, x_val):
        for start, end in self._omit_ranges:
            omit_length = (end - start) / 3
            omit_start = start + omit_length
            omit_end = omit_start + omit_length

            if omit_start <= x_val < omit_end:
                return True
        return False


    def data_to_fig_x(self, x_val):
        signal_x_axes = self.signal_x_axes
        signal_width = self.signal_width
        left_margin = self.left_margin

        return (x_val - signal_x_axes[0]) / (signal_x_axes[-1] - signal_x_axes[0] - self._shortened) * signal_width + left_margin

    def draw_signals(self, signals, labels):
        signal_height = self.signal_height
        top_margin = self.top_margin
        signal_amplitude = self.signal_amplitude
        color = self.color
        # t = self.signal_x_axes
        t = self._parse_signal.create_x_axes(self.signal_cycle - self._shortened)
        fig = self.fig

        for signal_idx, (label, signal) in enumerate(zip(labels, signals)):
            y_base = 1 - top_margin - (signal_idx + 1) * signal_height
            x_step = np.repeat(t, 2)[1:]
            y_step = np.repeat(signal, 2)[:-1]

            x_fig = self.data_to_fig_x(x_step)
            y_fig = y_base + y_step * signal_height * signal_amplitude

            points = np.array([x_fig, y_fig]).T.reshape(-1, 1, 2)
            segments = np.concatenate([points[:-1], points[1:]], axis=1)
            linestyles = ['-'] * len(segments)  # 默认实线

            for i in range(len(segments)):
                if self.is_omit(x_step[i]):
                    linestyles[i] = (0, (3, 2))
                    print(x_step[i])

            line = LineCollection(segments, linestyles=linestyles, alpha=0.9,transform=fig.transFigure, colors=[color] * len(segments))

            fig.add_artist(line)

            fig.text(
                x=self.left_margin * 0.8,
                y=y_base + signal_height * 0.3,
                s=label,
                ha='right',
                va='center',
                color=color,
                transform=fig.transFigure
            )

    def draw_dotted_lines(self, signals):
        bottom_margin = self.bottom_margin
        top_margin = self.top_margin
        filtered_edges = self.get_filtered_edges(signals)
        color = self.color
        fig = self.fig

        for x_pos, value in zip(filtered_edges, self._edge_points):
            x_fig = self.data_to_fig_x(x_pos)

            fig.add_artist(Line2D(
                [x_fig, x_fig], [bottom_margin * 0.8, 1 - top_margin],
                color=color,
                linestyle=(0, (3, 2)),
                alpha=0.6,
                transform=fig.transFigure
            ))

            fig.text(
                x=x_fig, y=1 - top_margin + 0.01,
                s=f"{value:.0f}",
                rotation=-90,
                ha='center',
                va='bottom',
                color=color,
                transform=fig.transFigure
            )

    def process(self, save_path, font_size=8, rc_param:dict=None):
        labels, x_axes, signals = self._parse_signal.get_signal_infos()
        self.signal_num = len(signals)
        self.signal_cycle = len(signals[0])

        # edge_points = list(sorted(set(int(x_axes[idx]) for signal in signals for idx in self.find_edges(signal))))
        # if edge_points[0] > 0:
        #     edge_points.insert(0, 0)
        # self.flag = False #edge_points[-1] < self.signal_cycle - 1
        # self._edge_points = edge_points
        self._edge_points = self.get_edge_points(x_axes, signals)

        adjusted_arr, shortened, adjusted_signals, omit_range = self.adjust_intervals(signals, threshold=8, zoom_factor=0.25, min_interval=5)
        signals = adjusted_signals
        original_paras = self.rc_param_original()
        self.rc_param_update(self.default_rc_params)
        if rc_param:
            self.rc_param_update(rc_param)

        self.create_figure(signals,0.3, 20)
        self.draw_signals(signals, labels)
        self.draw_dotted_lines(signals)
        self.save_signals(save_path, dpi=100)

        self.rc_param_update(original_paras)




if __name__ == '__main__':
    signal_config = {
        'timing': [
            ['Channel 1', 0, [40, 250, 350]],
            ['Channel 2', 1, [75, 125, 275]],
            ['Channel 3', 0, [50]],
            ['Channel 4', 1, [125, 175, 200, 300]],
            ['Channel 5', 0, [100, 150, 400,432]],
            ['Channel 6', 0, [100, 450]],
            ['Channel 7', 0, [80, 150, 340, 420]],
            ['Channel 8', 0, [230]],
            ['Channel 9', 1, [100, 150, 200]],
            ['Channel 10', 0, [30, 480]],
            ['Channel 11', 0, [10, 150, 200, 350, 400, 499]],
            ['Channel 12', 0, [100, 150]],
            ['Channel 13', 0, [100, 175, 325, 350]]
        ]
    }
    signal_cycle = 500
    signal_num = 32
    signal_config = DrawSignals.simulate_signals(signal_cycle, np.random.randint(1, 4, signal_num).tolist(), 1)


    path = r'../assert/template old.ini'
    ps = ParseSignalOld(path)

    path = r'../assert/template new long.ini'
    ps = ParseSignalNewLong(path)

    path = r'../assert/template new short.ini'
    ps = ParseSignalNewShort(path, section_name='timing', signal_cycle=signal_cycle, offset=0)

    # ps = ParseSignalEvk(signal_infos=signal_config, section_name='timing', signal_cycle=signal_cycle, offset=0)

    # dt = DrawSignals(plt=plt, parse_signal=ps)
    # dt = DrawSignalsSketchy(plt=plt, parse_signal=ps)
    dt = DrawSignalStrategyOmit(plt=plt, parse_signal=ps)
    save_path = '../output/timing.svg'
    dt.process(save_path)


    original_paras = dt.rc_param_original()
    new_paras = {
        'font.size': 6,
        'svg.fonttype': 'none',
        'axes.unicode_minus': False,
        'font.family': 'Calibri',
        # 'font.weight': 'light',
        'lines.linewidth': 0.8
    }
    dt.rc_param_update(new_paras)
    dt.show_signals()
    dt.rc_param_update(original_paras)
